/*
python3 -m http.server --cgi 8000

curl -F "file=@1K" http://192.168.1.249/cgi-bin/upload.cgi 
curl -F "file=@100K" http://192.168.1.249/cgi-bin/upload.cgi 
curl -F "file=@1M" http://192.168.1.249/cgi-bin/upload.cgi 
curl -F "file=@8M" http://192.168.1.249/cgi-bin/upload.cgi 
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>


#define MAX_FILENAME 256
#define UPLOAD_DIR "/tmp/update/"
int                    g_dbgfd;

void log_init()
{
    // TODO 如果没有fifo则创建
    g_dbgfd = open("/tmp/outfifo", O_RDWR);
}

// Function to find the boundary in the content type
// char *get_boundary(char *content_type) {
//     char *boundary = strstr(content_type, "boundary=");
//     if (boundary) {
//         return boundary + 9; // Skip "boundary="
//     }
//     return NULL;
// }


// Mocked get_boundary function, replace with the actual implementation
char* get_boundary(const char *content_type) {
    char *boundary_start = strstr(content_type, "boundary=");
    if (!boundary_start) return NULL;
    return boundary_start + strlen("boundary=");
}


// Function to find the filename in the content disposition
char *get_filename(char *content_disposition) {
    char *filename = strstr(content_disposition, "filename=\"");
    if (filename) {
        filename += 10; // Skip "filename=\""
        char *end = strchr(filename, '\"');
        if (end) {
            *end = '\0';
            return filename;
        }
    }
    return NULL;
}

char *pfile_buf;


void set_nonblocking_mode(FILE *file) {
    int fd = fileno(file);
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1) {
        perror("fcntl F_GETFL");
        exit(EXIT_FAILURE);
    }
    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
        perror("fcntl F_SETFL");
        exit(EXIT_FAILURE);
    }
}


void handle_upload() {
    char buffer[8192];
    char filename[MAX_FILENAME];
    char *content_length, *content_type;
    int len, bytes_read, total_bytes_read = 0;
    FILE *file;

    content_length = getenv("CONTENT_LENGTH");
    content_type = getenv("CONTENT_TYPE");
    dprintf(g_dbgfd, "len %s type %s\r\n", content_length, content_type);
    if (content_length == NULL || content_type == NULL) {
        printf("Content-Type: text/html\n\n");
        printf("<html><body><h1>Error: No content length or content type.</h1></body></html>\n");
        return;
    }

    len = atoi(content_length);
    if (len <= 0) {
        printf("Content-Type: text/html\n\n");
        printf("<html><body><h1>Error: Invalid content length.</h1></body></html>\n");
        return;
    }

    char *boundary = get_boundary(content_type);
    if (boundary == NULL) {
        printf("Content-Type: text/html\n\n");
        printf("<html><body><h1>Error: No boundary found.</h1></body></html>\n");
        return;
    }
    
    set_nonblocking_mode(stdin);

    struct timeval timeout;
    int fd = fileno(stdin);
    fd_set read_fds;
    FD_ZERO(&read_fds);
    FD_SET(fd, &read_fds);

    // 设置超时时间为5秒
    timeout.tv_sec = 10;
    timeout.tv_usec = 0;

    int retval = select(fd + 1, &read_fds, NULL, NULL, &timeout);


    // Read the data
    bytes_read = fread(buffer, 1, sizeof(buffer) - 1, stdin);
    if (bytes_read <= 0) {
        printf("Content-Type: text/html\n\n");
        printf("<html><body><h1>Error: No data read.</h1></body></html>\n");
        return;
    }
    buffer[bytes_read] = '\0';
    dprintf(g_dbgfd, "buffer %s", buffer);
    // Find the filename
    char *header_end = strstr(buffer, "\r\n\r\n");
    if (header_end == NULL) {
        printf("Content-Type: text/html\n\n");
        printf("<html><body><h1>Error: Malformed request.</h1></body></html>\n");
        return;
    }
    header_end += 4;

    char *filename_start = strstr(buffer, "filename=\"");
    if (filename_start) {
        filename_start += 10; // Skip 'filename="'
        char *filename_end = strchr(filename_start, '\"');
        if (filename_end) {
            int filename_len = filename_end - filename_start;
            if (filename_len < MAX_FILENAME) {
                strncpy(filename, filename_start, filename_len);
                filename[filename_len] = '\0';
            } else {
                printf("Content-Type: text/html\n\n");
                printf("<html><body><h1>Error: Filename too long.</h1></body></html>\n");
                return;
            }
        } else {
            printf("Content-Type: text/html\n\n");
            printf("<html><body><h1>Error: Filename end not found.</h1></body></html>\n");
            return;
        }
    } else {
        printf("Content-Type: text/html\n\n");
        printf("<html><body><h1>Error: Filename not found.</h1></body></html>\n");
        return;
    }

    // Create the upload directory if it doesn't exist
    mkdir(UPLOAD_DIR, 0755);

    // Save the file
    char filepath[MAX_FILENAME + sizeof(UPLOAD_DIR)];
    snprintf(filepath, sizeof(filepath), "%s%s", UPLOAD_DIR, filename);
    file = fopen(filepath, "wb");
    if (file != NULL) {
        char *file_content = header_end;
        int content_length = bytes_read - (header_end - buffer);

        // Check if the initial read already includes the boundary
        char *boundary_start = strstr(file_content, boundary);
        if (boundary_start && (boundary_start < file_content + content_length)) {
            content_length = boundary_start - file_content - 4; // Subtract \r\n-- before boundary
        }

        // Write the initial content read
        fwrite(file_content, 1, content_length, file);
        total_bytes_read += content_length;

        // Continue reading the rest of the file
        while (total_bytes_read < len) {
            bytes_read = fread(buffer, 1, sizeof(buffer), stdin);
            if (bytes_read <= 0) {
                break;
            }

            total_bytes_read += bytes_read;

            // If this is the last part, we need to trim the trailing boundary
            // if (total_bytes_read >= len) {
                buffer[bytes_read] = '\0'; // Ensure null termination
                boundary_start = strstr(buffer, boundary);
                if (boundary_start) {
                    bytes_read = boundary_start - buffer - 4; // Subtract \r\n-- before boundary
                }
            // }

            fwrite(buffer, 1, bytes_read, file);
        }

        fclose(file);

        // Response
        printf("Content-Type: text/html\n\n");
        printf("<html><body><h1>File uploaded successfully: %s</h1></body></html>\n", filepath);
    } else {
        printf("Content-Type: text/html\n\n");
        printf("<html><body><h1>Error: Could not save file.</h1></body></html>\n");
    }
}
int main() {
    log_init();
    dprintf(g_dbgfd, "%s() %d\r\n", __FUNCTION__, __LINE__);
    handle_upload();
    return 0;
}
